﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;

namespace Lenic.DI.Lifetimes
{
    /// <summary>
    /// 生存周期类型虚基类
    /// </summary>
    [DebuggerStepThrough]
    public abstract class LifetimeBase : ILifetime
    {
        #region Private Fields

        private event PreprocessNotifiedObject onBeforeResolve;

        private event ProcessNotifiedObject onRoundResolve;

        private event PostprocessNotifiedObject onAfterResolve;

        private Dictionary<MemberInfo, object> onBeforeResolveDic = new Dictionary<MemberInfo, object>();
        private Dictionary<MemberInfo, object> onRoundResolveDic = new Dictionary<MemberInfo, object>();
        private Dictionary<MemberInfo, object> onAfterResolveDic = new Dictionary<MemberInfo, object>();

        #endregion Private Fields

        #region ILifetime Members

        /// <summary>
        /// 获取或设置对象生成委托。
        /// </summary>
        public Delegate Function { get; set; }

        /// <summary>
        /// 获取 T 类型的实例对象。
        /// </summary>
        /// <typeparam name="T">待获取的目标类型</typeparam>
        /// <param name="name">用于区分的实例名称。</param>
        /// <param name="action">用于获取对象的委托方法。</param>
        /// <returns>获取得到的 T 类型的对象实例。</returns>
        T ILifetime.GetInstance<T>(string name, Func<Delegate, T> action)
        {
            Exception ex = null;

            if (onBeforeResolve != null)
                onBeforeResolve(this);

            object result = GetValue(name, action, ref ex);
            if (onRoundResolve != null)
                onRoundResolve(this, ex, ref result, typeof(T));

            var ei = new ExceptionInfo(ex);
            if (onAfterResolve != null)
                onAfterResolve(this, ei, ref result, typeof(T));

            if (ei.Rethrow)
                throw ei.Exception;

            return (T)result;
        }

        /// <summary>
        /// 获取与生存周期相关的扩展属性。
        /// </summary>
        public IDictionary<string, object> Tag { get; private set; }

        #endregion ILifetime Members

        #region INotifiedObject Members

        /// <summary>
        /// 对象解析前事件.
        /// </summary>
        public event PreprocessNotifiedObject OnBeforeResolve
        {
            add
            {
                MemberInfo mi = value.Method;
                if (!onBeforeResolveDic.ContainsKey(mi))
                {
                    onBeforeResolveDic[mi] = null;
                    onBeforeResolve += value;
                }
            }
            remove
            {
                if (onBeforeResolveDic.Remove(value.Method))
                    onBeforeResolve -= value;
            }
        }

        /// <summary>
        /// 对象解析时事件.
        /// </summary>
        public event ProcessNotifiedObject OnRoundResolve
        {
            add
            {
                MemberInfo mi = value.Method;
                if (!onRoundResolveDic.ContainsKey(mi))
                {
                    onRoundResolveDic[mi] = null;
                    onRoundResolve += value;
                }
            }
            remove
            {
                if (onRoundResolveDic.Remove(value.Method))
                    onRoundResolve -= value;
            }
        }

        /// <summary>
        /// 对象解析后事件.
        /// </summary>
        public event PostprocessNotifiedObject OnAfterResolve
        {
            add
            {
                MemberInfo mi = value.Method;
                if (!onAfterResolveDic.ContainsKey(mi))
                {
                    onAfterResolveDic[mi] = null;
                    onAfterResolve += value;
                }
            }
            remove
            {
                if (onAfterResolveDic.Remove(value.Method))
                    onAfterResolve -= value;
            }
        }

        #endregion INotifiedObject Members

        #region Entrance

        protected LifetimeBase()
        {
            Tag = new Dictionary<string, object>();
        }

        #endregion Entrance

        #region Abstract Members

        /// <summary>
        /// 从委托中解析获取对象的值.
        /// </summary>
        /// <typeparam name="T">待获取的目标类型</typeparam>
        /// <param name="name">用于区分的实例名称。</param>
        /// <param name="action">用于获取对象的委托方法。</param>
        /// <returns>获取得到的 T 类型的对象实例。</returns>
        protected abstract object GetValue<T>(string name, Func<Delegate, T> action);

        private object GetValue<T>(string name, Func<Delegate, T> action, ref Exception ex)
        {
            try
            {
                return GetValue(name, action);
            }
            catch (Exception e)
            {
                ex = e;
                return null;
            }
        }

        #endregion Abstract Members

        #region IDisposable 成员

        private bool isDisposed = false;

        public void Dispose()
        {
            if (!isDisposed)
            {
                Disposing();
                isDisposed = true;
            }
        }

        protected virtual void Disposing()
        {
        }

        #endregion IDisposable 成员
    }
}